home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / m2 / cat3src / cat / treelist.i < prev    next >
Text File  |  1997-10-26  |  67KB  |  2,031 lines

  1. IMPLEMENTATION MODULE treeList;
  2.  
  3. (*==============================================================*
  4.  * Modul:               CAT-Anzeigemodul fr Stichwortlisten    *
  5.  * Autor:               Dirk Steins                             *
  6.  * erstellt am:         8.8.1993                                *
  7.  * letzte Žnderung am:  10.08.1993                              *
  8.  * Version:             0.0                                     *
  9.  *==============================================================*
  10.  
  11.  *----------------------------------------------------------------------------
  12.  * Datum    Vers. Autor  Žnderung (Arbeitsbericht)
  13.  *----------------------------------------------------------------------------
  14.  * 08.08.93 0.0   DS     Erste Implementation erstellt
  15.  * 14.08.93 0.1   DS     Modul zeigt B„ume richtig an und funktioniert erstmal
  16.  * 06.06.95 0.2   DS     Fehler mit šberlappungen unter gewissen Umst„nden 
  17.  *                       gefunden und behoben
  18.  *                      
  19.  *----------------------------------------------------------------------------
  20.  *)
  21.  
  22. (*-- MM2-Module ------------------------------------------------------------*)
  23. FROM SYSTEM     IMPORT ADDRESS, ADR, TSIZE, CALLSYS, CADR;
  24. FROM Storage    IMPORT ALLOCATE, DEALLOCATE;
  25. IMPORT Block;
  26. IMPORT Lists;
  27. IMPORT GrafBase;
  28. IMPORT BinOps;
  29. IMPORT Strings;
  30. IMPORT StrConv;
  31. IMPORT MOSGlobals;
  32. IMPORT Keyboard;
  33. FROM Keyboard  IMPORT SpecialCode;
  34.  
  35. (*-- Cat-Module ------------------------------------------------------------*)
  36. FROM Void         IMPORT v;
  37.  
  38. IMPORT data;
  39. IMPORT dataSys;
  40. IMPORT EditTypes;
  41. IMPORT MTE;
  42. IMPORT VDIStandards;
  43. IMPORT MausTauschrsc;
  44. IMPORT CatTypes;
  45. IMPORT handlePool;
  46. IMPORT ConfVars;
  47. IMPORT WdwManager;
  48. IMPORT RectFuncs;
  49. IMPORT FontSelect;
  50. IMPORT CatGlobal;
  51. IMPORT grin;
  52. IMPORT Varnames;
  53. IMPORT GroupSelect;
  54.  
  55. (*-- Magic-Lib -------------------------------------------------------------*)
  56. IMPORT MagicStrings;
  57. IMPORT MagicAES;
  58. IMPORT MagicVDI;
  59. IMPORT MagicFSM;
  60. IMPORT MagicDOS;
  61. IMPORT MagicConvert;
  62.  
  63. (*-- Magic-Tools -----------------------------------------------------------*)
  64. IMPORT mtAppl;
  65. IMPORT mtArea;
  66. IMPORT mtUtils;
  67. IMPORT mtAlerts;
  68. IMPORT mtDials;
  69. IMPORT mtPopups;
  70.  
  71. (*-- Konstanten ------------------------------------------------------------*)
  72.  
  73. CONST   cElemLines  = 2;
  74.         cElemHDist  = 8;
  75.         cElemWDist  = 32;
  76.         
  77.         cMinX   = 8;
  78.         cMinY   = 8;
  79.  
  80. (*-- Typdefinitionen -------------------------------------------------------*)
  81.  
  82. TYPE    zoomModeType    = (zmNormal, zmZoom);
  83.  
  84. TYPE    tLine       = RECORD
  85.                         p1, p2 : GrafBase.Point;
  86.                       END;
  87.  
  88.         tLongLine   = RECORD
  89.                         p1, p2 : GrafBase.LongPnt;
  90.                       END;
  91.  
  92.         tShortText  = ARRAY [0..19] OF CHAR;
  93.  
  94.         treeElemPtr = POINTER TO treeElem;
  95.         treeElem    = RECORD
  96.                         msgNum  : CARDINAL;
  97.                         selected: BOOLEAN;
  98.                         width   : INTEGER;
  99.                         area    : GrafBase.LongRect;
  100.                         flags   : BITSET;       (* Die Bits der Nachricht *)
  101.                         name,
  102.                         betreff : tShortText;
  103.                         up, 
  104.                         down,
  105.                         left,
  106.                         right   : CARDINAL; (* Indizes in treeArray *)
  107.                       END;
  108.  
  109.         treeArrayType   = ARRAY [0..$FFFF] OF treeElem;
  110.         treeArrayPtr    = POINTER TO treeArrayType;
  111.  
  112.         treeOffsetArray = ARRAY [0..$FFFFFFFF] OF LONGINT;
  113.         treeOffsetArrayPtr = POINTER TO treeOffsetArray;
  114.         treeOffsetType  = RECORD
  115.                             size : LONGINT;
  116.                             array: treeOffsetArrayPtr;
  117.                           END;
  118.         treeOffsetPtr   = POINTER TO treeOffsetType;
  119.         
  120.         treeBuildType   = (tVertical, tHorizontal);
  121.  
  122.         treeWindow  = RECORD
  123.                         wdw         : INTEGER;      (* Windowhandle *)
  124.                         vdi         : INTEGER;      (* VDI-Handle   *)
  125.                         grinWindow  : INTEGER;      (* Das zugeh”rige Anzeigefenster *)
  126.                         butWork,                    (* Rechteck des Objektbaumes *)
  127.                         treeWork    : GrafBase.Rectangle; (* Workrectangle des Fensters *)
  128.                         number      : INTEGER;      (* Nummer des Fensters im Modul *)
  129.                         font, 
  130.                         fontSize    : INTEGER;      (* Font & Gr”že *)
  131.                         document    : GrafBase.LongRect;     
  132.                         grHandle    : handlePool.oneHandlePtr;      (* Gruppenhandle *)
  133.                         grName      : ARRAY [0..255] OF CHAR;       (* Gruppenname fr Titelzeile *)
  134.                         charHeight,                 (* Zeichensatzvariablen *)
  135.                         charWidth   : INTEGER;
  136.                         isFSM       : BOOLEAN;
  137.                         treeType    : treeBuildType;
  138.                         zoomMode    : zoomModeType;
  139.                         (* Jetzt die Daten fr den Baum *)
  140.                         elemHeight,
  141.                         elemDist,
  142.                         elemWDist,                  (* Gr”žen und Abst„nde der einzelnen Objekte *)
  143.                         elemHDist   : INTEGER;      (* Gr”žen und Abst„nde der einzelnen Objekte *)
  144.                         treeElems   : CARDINAL;
  145.                         tree        : treeArrayPtr;
  146.                         vertical    : treeOffsetPtr;
  147.                         horizontal  : treeOffsetPtr;
  148.                       END;
  149.  
  150.         treeWdwPtr  = POINTER TO treeWindow;
  151.  
  152.  
  153. (*-- Globale Variablen -----------------------------------------------------*)
  154.  
  155. VAR     windows         : Lists.List;
  156.         maxUpLevels     : INTEGER;
  157.         maxTreeDepth    : INTEGER;
  158.         notReadEff      : BITSET;
  159.  
  160.  
  161. (*-------------- Suchfunktionen in Liste -----------------------*)
  162.  
  163. TYPE intPtr     = POINTER TO INTEGER;
  164.      cardPtr    = POINTER TO CARDINAL;
  165.  
  166. (*$A+,Z-*)
  167. PROCEDURE FindWinCond(e, i : ADDRESS):BOOLEAN;
  168. (* Abbruchprozedur, wie in <Lists> gefordert *)
  169. BEGIN
  170.   RETURN treeWdwPtr(e)^.wdw = intPtr(i)^
  171. END FindWinCond;
  172.  
  173. PROCEDURE FindGroupCond (e, i : ADDRESS): BOOLEAN;
  174. BEGIN
  175.   RETURN treeWdwPtr(e)^.grHandle^.group = cardPtr(i)^
  176. END FindGroupCond;
  177.  
  178. (*$A=,Z=*)
  179.  
  180. TYPE NumSet  = SET OF [0..255];
  181.  
  182. VAR treeNums : NumSet;
  183.     globalNumber : INTEGER;
  184.     
  185. PROCEDURE FindNum () : INTEGER;
  186.   VAR i : INTEGER;
  187. BEGIN
  188.   IF (globalNumber >= 0) & 
  189.      ~ (globalNumber IN treeNums)
  190.   THEN
  191.     INCL (treeNums, globalNumber);
  192.     i := globalNumber;
  193.     globalNumber := -1;
  194.     RETURN i
  195.   END;
  196.   FOR i := 0 TO 255 DO
  197.     IF ~(i IN treeNums) THEN INCL (treeNums, i); RETURN i; END;
  198.   END;
  199. END FindNum;
  200.  
  201. PROCEDURE ClearNum (num : INTEGER);
  202. BEGIN
  203.   EXCL (treeNums, num);
  204. END ClearNum;
  205.  
  206. (*-- Baum positionieren ------------------------------------------------*)
  207.  
  208. (*-- Subfunktionen, die dynamische Array verwalten ---------------------*)
  209.  
  210. PROCEDURE createOffset (size: LONGINT): treeOffsetPtr;
  211.   VAR offset: treeOffsetPtr;
  212. BEGIN
  213.   ALLOCATE (offset, TSIZE (treeOffsetType));
  214.   IF offset = NIL THEN RETURN NIL END;
  215.   offset^.size := size;
  216.   ALLOCATE (offset^.array, size * TSIZE (LONGINT));
  217.   Block.Clear (offset^.array, size * TSIZE (LONGINT));
  218.   IF offset^.array = NIL THEN DEALLOCATE (offset, 0); RETURN NIL END;
  219.   RETURN offset;
  220. END createOffset;
  221.  
  222. PROCEDURE freeOffset (offset: treeOffsetPtr);
  223. BEGIN
  224.   DEALLOCATE (offset^.array, 0);
  225.   DEALLOCATE (offset, 0);
  226. END freeOffset;
  227.  
  228. PROCEDURE resetOffset (offset: treeOffsetPtr);
  229.   VAR i : LONGINT;
  230. BEGIN
  231.   WITH offset^ DO
  232.     FOR i := 0 TO offset^.size - 1 DO
  233.       array^[i] := cMinY;
  234.     END;
  235.   END;
  236. END resetOffset;
  237.  
  238. PROCEDURE currentPosition (offset: treeOffsetPtr; position: LONGINT): LONGINT;
  239. BEGIN
  240.   IF position >= offset^.size THEN RETURN 0 END;
  241.   RETURN offset^.array^[position];
  242. END currentPosition;
  243.  
  244. PROCEDURE setCurrentPosition (offset: treeOffsetPtr; index: LONGINT; value: LONGINT);
  245.   VAR newArray : treeOffsetArrayPtr;
  246.       newSize  : LONGINT;
  247. BEGIN
  248.   IF (index >= offset^.size)
  249.   THEN
  250.     (* Realloc, Array vergr”žern *)
  251.     newSize := index + index DIV 2;
  252.     ALLOCATE (newArray, newSize * TSIZE (LONGINT));
  253.     IF newArray = NIL THEN RETURN END;
  254.     Block.Clear (newArray, newSize * TSIZE (LONGINT));
  255.     Block.Copy (offset^.array, offset^.size * TSIZE (LONGINT), newArray);
  256.     DEALLOCATE (offset^.array, 0);
  257.     offset^.size := newSize;
  258.     offset^.array := newArray;
  259.   END;
  260.   offset^.array^[index] := value;
  261. END setCurrentPosition;
  262.  
  263. PROCEDURE sumOfPositions (offset: treeOffsetPtr; index: LONGINT): LONGINT;
  264.   VAR sum   : LONGINT;
  265.       i     : LONGINT;
  266.       stop  : LONGINT;
  267. BEGIN
  268.   sum := 0;
  269.   WITH offset^ DO
  270.     IF index > size 
  271.     THEN 
  272.       stop := size 
  273.     ELSE
  274.       stop := index;
  275.     END;
  276.     FOR i := 0 TO stop - 1 DO 
  277.       INC (sum, array^[i]);
  278.     END;
  279.   END;
  280.   RETURN sum;
  281. END sumOfPositions;
  282.  
  283. (* Routinen fr Verticalen (links nach rechts) Baum *)
  284.  
  285. (*-- Horizontale Position setzen ---------------------------------------*)
  286.  
  287. PROCEDURE setPositionsVertical (ptr: treeWdwPtr; idx: CARDINAL; level: LONGINT;
  288.                                 VAR maxWidth, maxHeight : LONGINT);
  289. BEGIN
  290.   WITH ptr^ DO
  291.     (* Addiere die Summe aller Breiten der Knoten bis zu dieser Tiefe und 
  292.      * benutze es als x-Position 
  293.      *)
  294.   WITH tree^[idx].area DO
  295.       x := (level * LONG(elemHDist)) + sumOfPositions (horizontal, level) + cMinX;
  296.       w := currentPosition (horizontal, level);
  297.       (* Jetzt maxHeight und maxWidth prfen 
  298.        *)
  299.       maxWidth := BinOps.HigherLInt (maxWidth, x + w);
  300.       maxHeight := BinOps.HigherLInt (maxHeight, y + h);
  301.     END;
  302.     (* Jetzt werden die Koordinaten von allen subTrees gesetzt *)
  303.     idx := tree^[idx].down;
  304.     WHILE idx < dataSys.notSaved DO
  305.       setPositionsVertical (ptr, idx, level+1, maxWidth, maxHeight);
  306.       idx := tree^[idx].right;
  307.     END;
  308.   END; (* WITH ptr^ DO *)
  309. END setPositionsVertical;
  310.  
  311. (*-- Subtree nach unten verschieben ------------------------------------*)
  312.  
  313. PROCEDURE shiftSubtreeVertical (ptr: treeWdwPtr; idx: CARDINAL; dif: LONGINT);
  314.   VAR i : CARDINAL;
  315. BEGIN
  316.   WITH ptr^ DO
  317.     INC (tree^[idx].area.y, dif);
  318.     i := tree^[idx].down;
  319.     WHILE i < dataSys.notSaved DO
  320.       shiftSubtreeVertical (ptr, i, dif);
  321.       i := tree^[i].right;
  322.     END;
  323.   END;
  324. END shiftSubtreeVertical;
  325.  
  326. (*-- Einen Node positionieren ------------------------------------------*)
  327.  
  328. PROCEDURE computePositionsVertical (ptr: treeWdwPtr; idx: CARDINAL; level: LONGINT): LONGINT;
  329.   VAR currentHpos,
  330.       currentVpos   : LONGINT;
  331.       firstKid, 
  332.       lastKid       : CARDINAL;
  333.       i             : CARDINAL;
  334.       j             : LONGINT;
  335.       depth         : LONGINT;
  336.       offset        : LONGINT;
  337.       pos           : LONGINT;
  338.       top,
  339.       bottom        : LONGINT;
  340. BEGIN
  341.   WITH ptr^ DO
  342.     depth := 0;
  343.     (* Get the current positions for this level *)
  344.     currentHpos := currentPosition (horizontal, level);
  345.     currentVpos := currentPosition (vertical, level);
  346.     (* set the current horizontal width to the max widths of all
  347.      * elements at this level 
  348.      *)
  349.     setCurrentPosition (horizontal, level, BinOps.HigherLInt (currentHpos, tree^[idx].area.w));
  350.     IF tree^[idx].down >= dataSys.notSaved
  351.     THEN
  352.       tree^[idx].area.y := currentVpos;
  353.     ELSE
  354.       (* if the node has subnodes, recursively figure the positions of each 
  355.        * subnode
  356.        *)
  357.       i := tree^[idx].down;
  358.       WHILE i < dataSys.notSaved DO
  359.         depth := BinOps.HigherLInt (computePositionsVertical (ptr, i, level+1), depth);
  360.         i := tree^[i].right;
  361.       END; (* WHILE *)
  362.       (* now that the vertical positions of all children are 
  363.        * known, find the vertical extent of all subnodes 
  364.        *)
  365.       i := tree^[idx].down;
  366.       firstKid := i;
  367.       WHILE i < dataSys.notSaved DO
  368.         lastKid := i;
  369.         i := tree^[i].right;
  370.       END;
  371.       (*
  372.       (* Top und Bottom berechnen *)
  373.       top := tree^[firstKid].area.y + tree^[firstKid].area.h DIV 2;
  374.       bottom := tree^[lastKid].area.y + tree^[lastKid].area.h DIV 2;
  375.       (* set the nodes position to the center of its subnodes 
  376.        *)
  377.       tree^[idx].area.y := (top DIV 2) + (bottom DIV 2) - (elemHeight DIV 2);
  378.       *)
  379.       top := tree^[firstKid].area.y;
  380.       bottom := tree^[lastKid].area.y + tree^[lastKid].area.h - 1;
  381.       tree^[idx].area.y := (top + bottom - LONG(elemHeight-1)) DIV 2;
  382.       (* if this position is less than the next available 
  383.        * position, correct it to be the next available
  384.        * position, calculate the amount by which all subnodes
  385.        * must be shifted, and shift the entire sub-tree.
  386.        *)
  387.       IF tree^[idx].area.y < currentVpos
  388.       THEN
  389.         offset := currentVpos - tree^[idx].area.y;
  390.         i := tree^[idx].down;
  391.         WHILE i < dataSys.notSaved DO
  392.           shiftSubtreeVertical (ptr, i, offset);
  393.           i := tree^[i].right;
  394.         END;
  395.         (* Adjust the next available space at all levels below 
  396.          * the current level
  397.          *)
  398.         FOR j := level+1 TO depth DO 
  399.           pos := currentPosition (vertical, j);
  400.           setCurrentPosition (vertical, j, pos+offset);
  401.         END (* FOR *);
  402.         (* set the nodes position 
  403.          *)
  404.         tree^[idx].area.y := currentVpos;
  405.       END (* if *);
  406.     END; (* if hasSubnodes *)
  407.     (* Record the current vertical position at this level 
  408.      *)
  409.     setCurrentPosition (vertical, level, tree^[idx].area.y + tree^[idx].area.h + LONG(elemDist));
  410.     RETURN BinOps.HigherLInt (depth, level);
  411.   END; (* WITH ptr^ DO *)
  412. END computePositionsVertical;
  413.  
  414. (* Routinen fr Horizontalen (oben nach unten) Baum *)
  415.  
  416. (*-- Horizontale Position setzen ---------------------------------------*)
  417.  
  418. PROCEDURE setPositionsHorizontal (ptr: treeWdwPtr; idx: CARDINAL; level: LONGINT;
  419.                                 VAR maxWidth, maxHeight : LONGINT);
  420. BEGIN
  421.   WITH ptr^ DO
  422.     (* Addiere die Summe aller H”hen der Knoten bis zu dieser Tiefe und 
  423.      * benutze es als y-Position 
  424.      *)
  425.     WITH tree^[idx].area DO
  426.       y := (level * LONG(elemHDist)) + sumOfPositions (vertical, level) + cMinY;
  427.       (* w := currentPosition (horizontal, level); *)
  428.       (* Jetzt maxHeight und maxWidth prfen 
  429.        *)
  430.       maxWidth := BinOps.HigherLInt (maxWidth, x + w);
  431.       maxHeight := BinOps.HigherLInt (maxHeight, y + h);
  432.     END;
  433.     (* Jetzt werden die Koordinaten von allen subTrees gesetzt *)
  434.     idx := tree^[idx].down;
  435.     WHILE idx < dataSys.notSaved DO
  436.       setPositionsHorizontal (ptr, idx, level+1, maxWidth, maxHeight);
  437.       idx := tree^[idx].right;
  438.     END;
  439.   END; (* WITH ptr^ DO *)
  440. END setPositionsHorizontal;
  441.  
  442. (*-- Subtree nach unten verschieben ------------------------------------*)
  443.  
  444. PROCEDURE shiftSubtreeHorizontal (ptr: treeWdwPtr; idx: CARDINAL; dif: LONGINT);
  445.   VAR i : CARDINAL;
  446. BEGIN
  447.   WITH ptr^ DO
  448.     INC (tree^[idx].area.x, dif);
  449.     i := tree^[idx].down;
  450.     WHILE i < dataSys.notSaved DO
  451.       shiftSubtreeHorizontal (ptr, i, dif);
  452.       i := tree^[i].right;
  453.     END;
  454.   END;
  455. END shiftSubtreeHorizontal;
  456.  
  457. (*-- Einen Node positionieren ------------------------------------------*)
  458.  
  459. PROCEDURE computePositionsHorizontal (ptr: treeWdwPtr; idx: CARDINAL; level: LONGINT): LONGINT;
  460.   VAR currentHpos,
  461.       currentVpos   : LONGINT;
  462.       firstKid, 
  463.       lastKid       : CARDINAL;
  464.       i             : CARDINAL;
  465.       j             : LONGINT;
  466.       depth         : LONGINT;
  467.       offset        : LONGINT;
  468.       pos           : LONGINT;
  469.       top,
  470.       bottom        : LONGINT;
  471. BEGIN
  472.   WITH ptr^ DO
  473.     depth := 0;
  474.     (* Get the current positions for this level *)
  475.     currentHpos := currentPosition (horizontal, level);
  476.     currentVpos := currentPosition (vertical, level);
  477.     (* set the current horizontal width to the max widths of all
  478.      * elements at this level 
  479.      *)
  480.     setCurrentPosition (vertical, level, BinOps.HigherLInt (currentVpos, tree^[idx].area.h));
  481.     IF tree^[idx].down >= dataSys.notSaved
  482.     THEN
  483.       tree^[idx].area.x := currentHpos;
  484.     ELSE
  485.       (* if the node has subnodes, recursively figure the positions of each 
  486.        * subnode
  487.        *)
  488.       i := tree^[idx].down;
  489.       WHILE i < dataSys.notSaved DO
  490.         depth := BinOps.HigherLInt (computePositionsHorizontal (ptr, i, level+1), depth);
  491.         i := tree^[i].right;
  492.       END; (* WHILE *)
  493.       (* now that the vertical positions of all children are 
  494.        * known, find the vertical extent of all subnodes 
  495.        *)
  496.       i := tree^[idx].down;
  497.       firstKid := i;
  498.       WHILE i < dataSys.notSaved DO
  499.         lastKid := i;
  500.         i := tree^[i].right;
  501.       END;
  502.       
  503.       top := tree^[firstKid].area.x;
  504.       bottom := tree^[lastKid].area.x + tree^[lastKid].area.w - 1  ;
  505.       tree^[idx].area.x := (top + bottom - (tree^[idx].area.w - 1)) DIV 2;
  506.       (* if this position is less than the next available 
  507.        * position, correct it to be the next available
  508.        * position, calculate the amount by which all subnodes
  509.        * must be shifted, and shift the entire sub-tree.
  510.        *)
  511.       IF tree^[idx].area.x < currentHpos
  512.       THEN
  513.         offset := currentHpos - tree^[idx].area.x;
  514.         i := tree^[idx].down;
  515.         WHILE i < dataSys.notSaved DO
  516.           shiftSubtreeHorizontal (ptr, i, offset);
  517.           i := tree^[i].right;
  518.         END;
  519.         (* Adjust the next available space at all levels below 
  520.          * the current level
  521.          *)
  522.         FOR j := level+1 TO depth DO 
  523.           pos := currentPosition (horizontal, j);
  524.           setCurrentPosition (horizontal, j, pos+offset);
  525.         END (* FOR *);
  526.         (* set the nodes position 
  527.          *)
  528.         tree^[idx].area.x := currentHpos;
  529.       END (* if *);
  530.     END; (* if hasSubnodes *)
  531.     (* Record the current vertical position at this level 
  532.      *)
  533.     setCurrentPosition (horizontal, level, tree^[idx].area.x + tree^[idx].area.w - 1 + LONG(elemDist));
  534.     RETURN BinOps.HigherLInt (depth, level);
  535.   END; (* WITH ptr^ DO *)
  536. END computePositionsHorizontal;
  537.  
  538. (*-- den ganzen Baum positionieren -------------------------------------*)
  539.  
  540. PROCEDURE posTree (ptr: treeWdwPtr);
  541.   VAR maxWidth,
  542.       maxHeight : LONGINT;
  543.       i         : CARDINAL;
  544.       extend    : ARRAY [0..3] OF GrafBase.Point;
  545.       maxW,
  546.       w         : INTEGER;
  547. BEGIN
  548.   WITH ptr^ DO
  549.     (* Set elem height und minWidth 
  550.      *)
  551.     CASE zoomMode OF
  552.       zmNormal: elemHeight := charHeight * cElemLines;
  553.                 elemDist   := charHeight * 2;
  554.                 elemHDist  := charWidth * cElemHDist; |
  555.       zmZoom  : elemHeight := charHeight;
  556.                 elemDist   := charHeight * 2;
  557.                 elemHDist  := charWidth * 3; 
  558.     ELSE
  559.     END;
  560.  
  561.     maxHeight := 0;
  562.     maxWidth  := 0;
  563.     maxW := 0;
  564.     (* set each nodes width and height 
  565.      *)
  566.     IF (mtAppl.Bitplanes = 1) 
  567.     THEN
  568.       IF (CatGlobal.treeTextCol > 0)
  569.       THEN
  570.         CatGlobal.treeBackCol := 0;
  571.       ELSE
  572.         IF CatGlobal.treeBackCol = 0 THEN CatGlobal.treeBackCol := 1 END;
  573.       END;
  574.       CatGlobal.treeLineCol := CatGlobal.treeTextCol;
  575.       CASE CatGlobal.treeUnreadEff OF
  576.         0 : notReadEff := {}; |
  577.         1 : notReadEff := {MagicVDI.Fat}; |
  578.         2 : notReadEff := {MagicVDI.Italic}; |
  579.         3 : notReadEff := {MagicVDI.Light}; |
  580.       ELSE
  581.         notReadEff := {};
  582.       END;
  583.     ELSE
  584.       notReadEff := {};
  585.     END;
  586.     IF mtAppl.Bitplanes = 1
  587.     THEN
  588.       (* Texteffect setzen *)
  589.       v.bset := MagicVDI.SetTexteffect (vdi, notReadEff);
  590.     END;
  591.     FOR i := 0 TO treeElems - 1 DO 
  592.       IF zoomMode = zmNormal
  593.       THEN
  594.         VDIStandards.InqTextextend (isFSM, vdi,  tree^[i].betreff, extend);
  595.         w := extend[1].x - extend[0].x;
  596.         VDIStandards.InqTextextend (isFSM, vdi,  tree^[i].name, extend);
  597.         w := BinOps.HigherInt (w, extend[1].x - extend[0].x);
  598.         maxW := BinOps.HigherInt (w, maxW);
  599.       ELSE
  600.         w := charWidth;
  601.       END;
  602.       maxW := BinOps.HigherInt (w, maxW);
  603.       
  604.       tree^[i].area.w := w;
  605.       tree^[i].area.h := elemHeight;
  606.     END;
  607.     IF mtAppl.Bitplanes = 1
  608.     THEN
  609.       (* Texteffect setzen *)
  610.       v.bset := MagicVDI.SetTexteffect (vdi, {});
  611.     END;
  612.     IF treeType = tHorizontal
  613.     THEN
  614.       FOR i := 0 TO treeElems - 1 DO
  615.         tree^[i].area.w := maxW;
  616.       END;
  617.     END;
  618.  
  619.     (* Reset the auxiliary tables 
  620.      *)
  621.     resetOffset (vertical);
  622.     resetOffset (horizontal);
  623.     IF treeType = tVertical
  624.     THEN
  625.       (* compute each node's x,y position
  626.        *)
  627.       v.lint := computePositionsVertical (ptr, 0, 0);
  628.       (* Jetzt noch die horizontalen Positionen setzen 
  629.        *)
  630.       setPositionsVertical (ptr, 0, 0, maxWidth, maxHeight);
  631.       (* set document size  
  632.        *)
  633.     ELSIF treeType = tHorizontal
  634.     THEN
  635.       (* compute each node's x,y position
  636.        *)
  637.       v.lint := computePositionsHorizontal (ptr, 0, 0);
  638.       (* Jetzt noch die horizontalen Positionen setzen 
  639.        *)
  640.       setPositionsHorizontal (ptr, 0, 0, maxWidth, maxHeight);
  641.       (* set document size  
  642.        *)
  643.     END;    
  644.     document.w := maxWidth + LONG(charWidth) - 1;
  645.     document.h := maxHeight + LONG(charHeight) - 1;
  646.   END;
  647. END posTree;
  648.  
  649. (* ---------------------- Font-Funktionen ----------------------- *)
  650.  
  651. PROCEDURE iTreeSetFont (wdw : INTEGER; fnt, fntSize : INTEGER; redraw: BOOLEAN);
  652. (* Setzt den Font fr das Stichwortlistenfenster *)
  653.   VAR r : GrafBase.Rectangle;
  654.       ptr : treeWdwPtr;
  655.       varName : CatTypes.String255;
  656.       place   : GrafBase.Rectangle;
  657.       i       : CARDINAL;
  658.       maxWidth,
  659.       maxHeight : LONGINT;
  660. BEGIN
  661.   IF handlePool.FindEntry (ADR(wdw), FindWinCond, windows, ptr)
  662.   THEN
  663.     WITH ptr^ DO
  664.       font := fnt;
  665.       fontSize := fntSize;
  666.       FontSelect.SetFont (vdi, font, fontSize, TRUE, v.bool, isFSM, charWidth, charHeight);
  667.       (* Jetzt ist der Font gesetzt. Jetzt noch Window snappen und dann neu
  668.        * zeichnen lassen 
  669.        *)
  670.       Strings.Concat (cTreeFont, StrConv.IntToStr (number, 0), varName, v.bool);
  671.       v.bool := ConfVars.SetConfigInt (varName, font);
  672.       Strings.Concat (cTreeSize, StrConv.IntToStr (number, 0), varName, v.bool);
  673.       v.bool := ConfVars.SetConfigInt (varName, fontSize);
  674.       (* Jetzt habe ich einen Baum im Speicher, der mit Indizes arbeitet.
  675.        * Also k”nnen wir jetzt daran gehen, diese Objekte alle zu plazieren.
  676.        * Das geht am besten mit einer rekursiven Prozedur, die sowohl die Breite 
  677.        * als auch die H”he eines Eintrages zurckliefert
  678.        *)
  679.       
  680.       posTree (ptr);
  681.       WdwManager.SetNewDocument (wdw, document, FALSE);
  682.       WdwManager.SetDocumentParms (wdw, 1, 1);
  683.       (* Damit die Scrollbereiche neu berechnet werden *)
  684.       WdwManager.GetWdwSize (wdw, r);
  685.       WdwManager.SetWdwSize (wdw, r);
  686.  
  687.       IF redraw THEN 
  688.         WdwManager.RedrawWdw (wdw, treeWork);
  689.       END;
  690.     END; (* WITH ed^ DO *)
  691.   END;
  692. END iTreeSetFont;
  693.  
  694. (* Ich brauche Prozeduren, die folgende Funktionen erfllen:
  695.  * 
  696.  * - schneidet eine Linie ein Rechteck? (Redraw)
  697.  *   Dies l”sen wir einfach ber Rcintersect. Ist zwar nicht 100%ig exakt, 
  698.  *   aber schneller. Und eine vollst„ndige šberprfung w„re langsamer als 
  699.  *   ein paar Linien zus„tzlich ber das VDI zeichnen zu lassen. 
  700.  * - wo verl„žt eine Linie ein Rechteck ? (Linienzeichnen) 
  701.  *   Siehe GetIntersection
  702.  * - befindet sich ein Element in einem Rechteck (Rechteckberschneidung, Redraw)
  703.  *   wird gel”st ber RcIntersect (ClipRect)
  704.  * - Zeichnen eines Elementes und der Verbindungslinien von/zu diesem Element
  705.  *)
  706.  
  707. (*
  708. PROCEDURE GetIntersection (VAR line : tLine; r: GrafBase.Rectangle);
  709. (* Berechnet den Schnittpunkt einer Linie line (x,y) -> (w,h) mit
  710.  * einer der Seiten des Rechtecks r. Einer der beiden Endpunkte liegt dabei 
  711.  * innerhalb des Rechtecks r.
  712.  * ACHTUNG: Diese Routine ist nicht allgemein einsetzbar, da sie erstens
  713.  * nur den Schnittpunkt mit der linken oder rechten Seite des Rechtecks (bzw.
  714.  * dessen Verl„ngerung!) berechnet, und zweitens mit šberlappungen nicht 
  715.  * zurechtkommt, d.h. ein Punkt muž mit den x-Koordinaten aužerhalb des 
  716.  * Rechtecks liegen. Fr den geplanten Zweck ist das aber vollkommen
  717.  * ausreichend und schneller!
  718.  *)
  719.  VAR po1, po2, po3 : GrafBase.Point;
  720. BEGIN
  721.   (* Erstmal den Punkt herausfinden, der innerhalb des Rechtecks liegt *)
  722.   WITH line DO
  723.     IF RectFuncs.IsInRect (p1.x, p1.y, r)
  724.     THEN
  725.       po1 := p1; 
  726.       po2 := p2; 
  727.     ELSE
  728.       po1 := p2; 
  729.       po2 := p1; 
  730.     END;
  731.   END;
  732.   (* Jetzt herausfinden, ob wir die rechte oder linke Begrenzungslinie
  733.    * des Rechtecks nehmen. po2 ist der Punkt, der nicht im Rechteck liegt
  734.    *)
  735.   IF po2.x < r.x
  736.   THEN
  737.     (* Die linke Senkrechte des Rechtecks nehmen *)
  738.     po3.x := r.x;
  739.   ELSE
  740.     (* Die rechte Senkrechte des Rechtecks nehmen *)
  741.     po3.x := r.x + r.w - 1;
  742.   END;
  743.   IF po2.x = po1.x
  744.   THEN
  745.     po3.y := po2.y  (* Linie ist eine Senkrechte *)
  746.   ELSE
  747.     IF po2.y > po1.y
  748.     THEN
  749.       po3.y := SHORT(INT((FLOAT(po2.y - po1.y) / FLOAT(po2.x - po1.x)) * FLOAT(po3.x - po2.x))) + po2.y;
  750.     ELSE
  751.       po3.y := SHORT(INT((FLOAT(po1.y - po2.y) / FLOAT(po1.x - po2.x)) * FLOAT(po3.x - po2.x))) + po2.y;
  752.     END;
  753.   END;
  754.   (* So, jetzt haben wir den neuen Punkt. Die Linie aužerhalb geht jetzt 
  755.    * von po3 nach po2
  756.    *)
  757.   WITH line DO
  758.     p1 := po3;
  759.     p2 := po2;
  760.   END;
  761. END GetIntersection;
  762. *)
  763.  
  764. PROCEDURE MidPointV (r : GrafBase.LongRect; right: BOOLEAN): GrafBase.LongPnt;
  765. (* Berechnet den Mittelpunkt eines Rechtecks 
  766.  *)
  767.   VAR p : GrafBase.LongPnt;
  768. BEGIN
  769.   IF right
  770.   THEN 
  771.     p.x := r.x + r.w + 3;
  772.   ELSE
  773.     p.x := r.x - 3;
  774.   END;
  775.   p.y := r.y + (r.h  DIV 2);
  776.   RETURN p
  777. END MidPointV;
  778.  
  779. PROCEDURE MidPointH (r : GrafBase.LongRect; down: BOOLEAN): GrafBase.LongPnt;
  780. (* Berechnet den Mittelpunkt eines Rechtecks 
  781.  *)
  782.   VAR p : GrafBase.LongPnt;
  783. BEGIN
  784.   IF down
  785.   THEN 
  786.     p.y := r.y + r.h + 3;
  787.   ELSE
  788.     p.y := r.y - 3;
  789.   END;
  790.   p.x := r.x + (r.w  DIV 2);
  791.   RETURN p
  792. END MidPointH;
  793.  
  794. PROCEDURE ClipLongRect (frame: GrafBase.LongRect; clip: GrafBase.LongRect): GrafBase.LongRect;
  795. (* clippt das Rechteck frame auf das Rechteck clip
  796.  *)
  797. BEGIN
  798.   WITH frame DO
  799.     IF x<clip.x THEN w:=w-clip.x+x; x:=clip.x END;
  800.     IF y<clip.y THEN h:=h-clip.y+y; y:=clip.y END;
  801.     IF (w<0) OR (h<0) THEN w:=0;h:=0 END;
  802.     IF (x+w)>(clip.x+clip.w) THEN w:=clip.x+clip.w-x END;
  803.     IF (y+h)>(clip.y+clip.h) THEN h:=clip.y+clip.h-y END;
  804.     IF (w<0) OR (h<0) THEN w:=0;h:=0 END;
  805.   END;
  806.   RETURN frame;
  807. END ClipLongRect;
  808.  
  809. PROCEDURE ShortFrame (frame: GrafBase.LongRect): GrafBase.Rectangle;
  810. (*$R-*)
  811.   VAR r: GrafBase.Rectangle;
  812. BEGIN
  813.   r.x := SHORT (frame.x);
  814.   r.y := SHORT (frame.y);
  815.   r.w := SHORT (frame.w);
  816.   r.h := SHORT (frame.h);
  817.   RETURN r;
  818. END ShortFrame;
  819. (*$R=*)
  820.  
  821. (*-- drawing primitives ----------------------------------------------------*)
  822.  
  823. PROCEDURE Line (vdi: INTEGER; line : tLine; col, style: INTEGER);
  824. BEGIN
  825.  (* Erstmal Linewidth setzen *)
  826.  v.int := MagicVDI.SetLinewidth (vdi, 1);
  827.  (* Linienstil setzen (geht nur bei Dicke 1, wird sonst ignoriert) *)
  828.  v.int := MagicVDI.SetLinetype (vdi, style);
  829.  IF (col > 1) & (mtAppl.Bitplanes = 1)
  830.  THEN
  831.    (* Statt Farbe machen wir die Linie dicker *)
  832.    v.int := MagicVDI.SetLinewidth (vdi, 2);
  833.  ELSE
  834.    (* Linienfarbe setzen *)
  835.    v.int := MagicVDI.SetLinecolor (vdi, col);
  836.  END;
  837.  MagicVDI.Polyline (vdi, 2, line);
  838. END Line;
  839.  
  840. PROCEDURE Frame (vdi: INTEGER; col: INTEGER; x, y, w, h, times, style: INTEGER);
  841. (* Zeichnet einen Rahmen, times bestimmt die Dicke 
  842.  * Direkter VDI-Call, damit nicht ein tempor„res Linearray
  843.  * angelegt werden muž
  844.  *)
  845.  
  846. VAR i: INTEGER;
  847.     (*$Reg*)  a: INTEGER;
  848.     b: INTEGER;
  849. BEGIN
  850.  (* Erstmal Linewidth setzen *)
  851.  v.int := MagicVDI.SetLinewidth (vdi, 1);
  852.  (* Linienfarbe setzen *)
  853.  v.int := MagicVDI.SetLinecolor (vdi, col);
  854.  (* Linienstil setzen *)
  855.  v.int := MagicVDI.SetLinetype (vdi, style);
  856.  a:= 0;  b:= 0;
  857.  DEC (x);  DEC (y);  INC (w, 2);  INC (h, 2);
  858.  FOR i:= 1 TO times DO
  859.   DEC (x);  DEC (y);  INC (w, 2);  INC (h, 2);
  860.   MagicVDI.VDIPtsIn[0 + a]:= x;
  861.   MagicVDI.VDIPtsIn[1 + a]:= y;
  862.   MagicVDI.VDIPtsIn[2 + a]:= x + w;
  863.   MagicVDI.VDIPtsIn[3 + a]:= y;
  864.   MagicVDI.VDIPtsIn[4 + a]:= MagicVDI.VDIPtsIn[2 + a]; (* x + w; *)
  865.   MagicVDI.VDIPtsIn[5 + a]:= y + h;
  866.   MagicVDI.VDIPtsIn[6 + a]:= x;
  867.   MagicVDI.VDIPtsIn[7 + a]:= MagicVDI.VDIPtsIn[5 + a]; (* y + h; *)
  868.   MagicVDI.VDIPtsIn[8 + a]:= x;
  869.   MagicVDI.VDIPtsIn[9 + a]:= y;
  870.   INC (a, 10);  INC (b, 5);
  871.  END;
  872.  MagicVDI.VDICall(6, b, 0, 0, vdi);
  873. END Frame;
  874.  
  875. PROCEDURE drawElement (ptr: treeWdwPtr; idx : CARDINAL; clip : GrafBase.Rectangle);
  876. (* Diese Prozedur zeichnet ein Element oder seine Verbindungslinie, 
  877.  * wenn es im Cliprechteck liegt
  878.  *)
  879.   VAR line : tLine;
  880.       lline: tLongLine;
  881.       fill : GrafBase.Rectangle;
  882.       lClip,
  883.       lfill,
  884.       frame: GrafBase.LongRect;
  885.       mess : data.MessageType;
  886.       text : CatTypes.String127;
  887.       base : GrafBase.LongPnt;
  888.       col,
  889.       style: INTEGER;
  890. BEGIN
  891.   WITH ptr^ DO
  892.     WITH tree^[idx] DO
  893.       IF up < dataSys.notSaved
  894.       THEN
  895.         IF treeType = tVertical 
  896.         THEN
  897.           (* Linie berechnen *)
  898.           lline.p1 := MidPointV (tree^[up].area, TRUE);
  899.           lline.p2 := MidPointV (area, FALSE);
  900.         ELSIF treeType = tHorizontal
  901.         THEN
  902.           lline.p1 := MidPointH (tree^[up].area, TRUE);
  903.           lline.p2 := MidPointH (area, FALSE);
  904.         END;
  905.         (* Jetzt Schnittpunkte berechnen *)
  906.         (* Aus der Linie auch noch kurz ein Rechteck machen *)
  907.         frame := GrafBase.LFramePoints (lline.p1, lline.p2);
  908.         (* Jetzt Gesamtbereich des Elements berechnen *)
  909.         lfill := area;
  910.         (* Rahmen ist um zwei Pixel aužerhalb *)
  911.         DEC (lfill.x,2); DEC (lfill.y, 2); 
  912.         INC (lfill.w,5); INC (lfill.h, 5); 
  913.         frame := GrafBase.LFrameRects (lfill, frame);
  914.       ELSE
  915.         frame := area;
  916.         DEC (frame.x, 2);
  917.         DEC (frame.y, 2);
  918.         INC (frame.w, 5);
  919.         INC (frame.h, 5);
  920.       END;
  921.       (* Jetzt aus den relativen Koordinaten die absoluten berechnen *)
  922.       frame.x := frame.x - document.x + LONG(treeWork.x);
  923.       frame.y := frame.y - document.y + LONG(treeWork.y);
  924.       base.x := LONG(treeWork.x) - document.x;
  925.       base.y := LONG(treeWork.y) - document.y;
  926.       (*
  927.       frame := GrafBase.TransRect (frame, base);
  928.       *)
  929.       (* So, und jetzt nachsehen, ob davon ein Teil in der Cliparea ist *)
  930.       lClip := GrafBase.LongFrame (clip);
  931.       frame := GrafBase.LClipRect (frame, lClip);
  932.       IF (frame.w # 0) OR (frame.h # 0)
  933.       THEN
  934.         (* Ok, wir mssen zeichnen *)
  935.         col := CatGlobal.treeTextCol;
  936.         style := 1;
  937.         IF up < dataSys.notSaved THEN 
  938.           INC (lline.p1.x, base.x);
  939.           INC (lline.p1.y, base.y);
  940.           INC (lline.p2.x, base.x);
  941.           INC (lline.p2.y, base.y);
  942.           (* Jetzt Koordinaten auf short wandeln *)
  943.           line.p1.x := SHORT(BinOps.LowerLInt (lline.p1.x, 32767));
  944.           line.p1.y := SHORT(BinOps.LowerLInt (lline.p1.y, 32767));
  945.           line.p2.x := SHORT(BinOps.LowerLInt (lline.p2.x, 32767));
  946.           line.p2.y := SHORT(BinOps.LowerLInt (lline.p2.y, 32767));
  947.           (* Linie noch etwas absetzen *)
  948.           IF treeType = tVertical
  949.           THEN
  950.             INC (line.p1.x, 3);
  951.             DEC (line.p2.x, 3);
  952.           ELSIF treeType = tHorizontal
  953.           THEN
  954.             INC (line.p1.y, 3);
  955.             DEC (line.p2.y, 3);
  956.           END;
  957.           (* Erstmal sehen, ob das Stichwort ge„ndert wurde *)
  958.           IF ~Strings.StrEqual (betreff, tree^[up].betreff)
  959.           THEN
  960.             col := CatGlobal.treeLineCol;
  961.             IF mtAppl.Bitplanes = 1
  962.             THEN
  963.               style := MagicVDI.User; 
  964.             END;
  965.           END;
  966.           Line (vdi, line, col, style);
  967.         END;
  968.         (* Jetzt das Element *)
  969.         (* Farbe setzen *)
  970.         v.int := MagicVDI.SetTextcolor (vdi, CatGlobal.treeTextCol);
  971.         (* Rahmen um Element zeichnen *)
  972.         lfill := area;
  973.         INC (lfill.x, base.x);
  974.         INC (lfill.y, base.y);
  975.         (* Jetzt daraus ein kleines Rechteck machen *)
  976.         fill := ShortFrame (lfill);    (* Hier eigene Funktion einsetzen *)
  977.         Frame (vdi, col, fill.x, fill.y, fill.w, fill.h, 1, style);
  978.         IF zoomMode = zmNormal
  979.         THEN
  980.           (* Jetzt Text ausgeben *)
  981.           IF ~(dataSys.bGelesen IN flags) 
  982.           THEN
  983.             IF mtAppl.Bitplanes = 1
  984.             THEN
  985.               (* Texteffect setzen *)
  986.               v.bset := MagicVDI.SetTexteffect (vdi, notReadEff);
  987.             ELSE
  988.               (* Farbe setzen *)
  989.               v.int := MagicVDI.SetTextcolor (vdi, CatGlobal.treeUnreadCol);
  990.             END;
  991.           ELSE
  992.             v.bset := MagicVDI.SetTexteffect (vdi, {});
  993.           END;
  994.           v.int := MagicVDI.SetWritemode (vdi, MagicVDI.TRANSPARENT);
  995.           VDIStandards.Text (isFSM, vdi, SHORT(base.x + area.x), SHORT(base.y + area.y) + charHeight-1, name);
  996.           VDIStandards.Text (isFSM, vdi, SHORT(base.x + area.x), SHORT(base.y + area.y) + 2*charHeight-1, betreff);
  997.         END;
  998.         (* Wenn es selektiert ist, dann invertieren wir es einfach *)
  999.         IF selected
  1000.         THEN
  1001.           (* Writemode auf XOR und area mit Schwarz fllen *)
  1002.           v.int := MagicVDI.SetWritemode (vdi, MagicVDI.XOR);
  1003.           v.int := MagicVDI.SetFillcolor (vdi, MagicAES.BLACK);
  1004.           (* fill ist schon gesetzt, nur noch absolutes Rechteck daraus machen 
  1005.            *)
  1006.           fill.w := fill.x + SHORT(area.w); 
  1007.           fill.h := fill.y + SHORT(area.h);
  1008.           MagicVDI.FillRectangle (vdi, fill); 
  1009.           v.int := MagicVDI.SetFillcolor (vdi, CatGlobal.treeBackCol);
  1010.         END;
  1011.         v.int := MagicVDI.SetWritemode (vdi, MagicVDI.REPLACE);
  1012.         IF ~(dataSys.bGelesen IN flags) 
  1013.         THEN
  1014.           (* Texteffect und Farbe zurcksetzen *)
  1015.           IF mtAppl.Bitplanes = 1
  1016.           THEN
  1017.             (* Texteffect setzen *)
  1018.             v.bset := MagicVDI.SetTexteffect (vdi, {});
  1019.           ELSE
  1020.             (* Farbe setzen *)
  1021.             v.int := MagicVDI.SetTextcolor (vdi, CatGlobal.treeTextCol);
  1022.           END;
  1023.         END;
  1024.       END;
  1025.     END;
  1026.   END;
  1027. END drawElement;
  1028.  
  1029. PROCEDURE drawElemTree (ptr: treeWdwPtr; idx: CARDINAL; clip: GrafBase.Rectangle);
  1030. (* Rekursive Prozedur, die nur dazu da ist, den Baum zu durchlaufen 
  1031.  *)
  1032. BEGIN
  1033.   WITH ptr^ DO
  1034.     WHILE idx < dataSys.notSaved DO
  1035.       drawElement (ptr, idx, clip);
  1036.       IF tree^[idx].down < dataSys.notSaved
  1037.       THEN
  1038.         (* in die Tiefe gehen und die Teile zeichnen *)
  1039.         drawElemTree (ptr, tree^[idx].down, clip);
  1040.       END;
  1041.       idx := tree^[idx].right;
  1042.     END;
  1043.   END;
  1044. END drawElemTree;
  1045.  
  1046. PROCEDURE drawTreeWdw (wdw, vdiH : INTEGER; special : ADDRESS; frame : GrafBase.Rectangle);
  1047.   VAR ptr : treeWdwPtr;
  1048.       clip,
  1049.       fill: GrafBase.Rectangle;
  1050. BEGIN
  1051.   ptr := treeWdwPtr (special);
  1052.   WITH ptr^ DO
  1053.     IF (mtAppl.Bitplanes = 1) 
  1054.     THEN
  1055.       IF (CatGlobal.treeTextCol > 0)
  1056.       THEN
  1057.         CatGlobal.treeBackCol := 0;
  1058.       ELSE
  1059.         IF CatGlobal.treeBackCol = 0 THEN CatGlobal.treeBackCol := 1 END;
  1060.       END;
  1061.       CatGlobal.treeLineCol := CatGlobal.treeTextCol;
  1062.       CASE CatGlobal.treeUnreadEff OF
  1063.         0 : notReadEff := {}; |
  1064.         1 : notReadEff := {MagicVDI.Fat}; |
  1065.         2 : notReadEff := {MagicVDI.Italic}; |
  1066.         3 : notReadEff := {MagicVDI.Light}; |
  1067.       ELSE
  1068.         notReadEff := {};
  1069.       END;
  1070.     ELSE
  1071.       notReadEff := {};
  1072.     END;
  1073.     clip := frame;
  1074.     IF RectFuncs.rcIntersect (treeWork, frame)
  1075.     THEN
  1076.       clip := RectFuncs.ClipRect (treeWork, frame);
  1077.       INC (clip.w,2);
  1078.  
  1079.       (* Jetzt den Hintergrund l”schen *)
  1080.       
  1081.       fill := clip;
  1082.       fill.w := clip.x + clip.w - 1; 
  1083.       fill.h := clip.y + clip.h -1;
  1084.      
  1085.       v.int := MagicVDI.SetFillcolor (vdi, CatGlobal.treeBackCol);
  1086.       MagicVDI.FillRectangle(vdi, fill);
  1087.       
  1088.       (* Und jetzt Elemente zeichnen *)
  1089.       drawElemTree (ptr, 0, clip);
  1090.     END;
  1091.   END;
  1092. END drawTreeWdw;
  1093.  
  1094. PROCEDURE centerSelection (ptr : treeWdwPtr; redraw: BOOLEAN);
  1095.  VAR  i  : CARDINAL;
  1096.       lr : GrafBase.LongRect;
  1097.       lt : GrafBase.LongRect;
  1098.       lc : GrafBase.LongRect;
  1099.       visible: BOOLEAN;
  1100. BEGIN
  1101.   WITH ptr^ DO
  1102.     i := 0; 
  1103.     WHILE (i < treeElems) & ~(tree^[i].selected) DO INC (i) END;
  1104.     IF i < treeElems
  1105.     THEN
  1106.       (* Wir haben eine selektierte Nachricht *)
  1107.       lr := tree^[i].area;
  1108.       DEC (lr.x, 2);
  1109.       DEC (lr.y, 2);
  1110.       INC (lr.w, 5);
  1111.       INC (lr.h, 5);
  1112.       lt := GrafBase.LongFrame (treeWork);
  1113.       lr.x := lr.x - document.x + lt.x;
  1114.       lr.y := lr.y - document.y + lt.y;
  1115.       (* Jetzt prfen, ob es sichtbar ist *)
  1116.       lc := ClipLongRect (lr, lt);
  1117.       visible := (lc.w # 0) & (lc.h # 0);
  1118.       IF ~visible
  1119.       THEN
  1120.         (* document.x und .y umsetzen *)
  1121.         lr := tree^[i].area;
  1122.         document.x := BinOps.HigherLInt (lr.x - lt.w DIV 2, 0);
  1123.         document.x := BinOps.HigherLInt (0, BinOps.LowerLInt (document.x, document.w - lt.w));
  1124.         document.y := BinOps.HigherLInt (lr.y - lt.h DIV 2, 0);
  1125.         document.y := BinOps.HigherLInt (0, BinOps.LowerLInt (document.y, document.h - lt.h));
  1126.         IF redraw
  1127.         THEN
  1128.           (* WdwManager.FullRedrawWdw (wdw); *)
  1129.         END;
  1130.       END;      
  1131.       WdwManager.SetNewDocument (wdw, document, redraw);
  1132.     END;
  1133.   END;
  1134. END centerSelection;
  1135.  
  1136. PROCEDURE getEntryArea (ptr: treeWdwPtr; idx: CARDINAL; VAR r: GrafBase.Rectangle; VAR visible: BOOLEAN);
  1137.   VAR lr : GrafBase.LongRect;
  1138.       lt : GrafBase.LongRect;
  1139.       lc : GrafBase.LongRect;
  1140. BEGIN
  1141.   WITH ptr^ DO
  1142.     lr := tree^[idx].area;
  1143.     DEC (lr.x, 2);
  1144.     DEC (lr.y, 2);
  1145.     INC (lr.w, 5);
  1146.     INC (lr.h, 5);
  1147.     lt := GrafBase.LongFrame (treeWork);
  1148.     lr.x := lr.x - document.x + lt.x;
  1149.     lr.y := lr.y - document.y + lt.y;
  1150.     (* Jetzt prfen, ob es sichtbar ist *)
  1151.     lc := ClipLongRect (lr, lt);
  1152.     visible := (lc.w # 0) & (lc.h # 0);
  1153.     IF visible 
  1154.     THEN
  1155.       r := ShortFrame (lr);
  1156.     END;
  1157.   END;
  1158. END getEntryArea;
  1159.  
  1160. PROCEDURE redrawEntry (ptr : treeWdwPtr; entry: CARDINAL);
  1161. (* Zeichnet einen Eintrag OHNE seine Linie neu *)
  1162.   VAR rect : GrafBase.Rectangle;
  1163.       vis  : BOOLEAN;
  1164. BEGIN
  1165.   WITH ptr^ DO
  1166.     getEntryArea (ptr, entry, rect, vis);
  1167.     IF vis
  1168.     THEN
  1169.       WdwManager.RedrawWdw (wdw, rect);
  1170.       WdwManager.SetClip (vdi, treeWork, TRUE);
  1171.     END;
  1172.   END;
  1173. END redrawEntry;
  1174.  
  1175. PROCEDURE deselectEntries (ptr: treeWdwPtr);
  1176.   VAR idx : CARDINAL;
  1177.       clip,
  1178.       r   : GrafBase.Rectangle;
  1179.       vis,
  1180.       first: BOOLEAN;
  1181. BEGIN
  1182.   WITH ptr^ DO
  1183.     first := TRUE;
  1184.     FOR idx := 0 TO treeElems - 1 DO
  1185.       IF tree^[idx].selected
  1186.       THEN
  1187.         tree^[idx].selected := FALSE;
  1188.         getEntryArea (ptr, idx, r, vis);
  1189.         IF vis
  1190.         THEN
  1191.           IF first
  1192.           THEN
  1193.             clip := r;
  1194.             first := FALSE;
  1195.           ELSE
  1196.             clip := GrafBase.FrameRects (clip, r);
  1197.           END;
  1198.         END;
  1199.       END;
  1200.     END;
  1201.     IF ~first THEN WdwManager.RedrawWdw (wdw, clip); END;
  1202.   END;
  1203. END deselectEntries;
  1204.  
  1205. PROCEDURE findEntry (ptr:treeWdwPtr; x, y: INTEGER; VAR idx: CARDINAL): BOOLEAN;
  1206.  VAR i : CARDINAL;
  1207.      r : GrafBase.Rectangle;
  1208.      vis : BOOLEAN;
  1209. BEGIN
  1210.   WITH ptr^ DO
  1211.     FOR i := 0 TO treeElems - 1 DO
  1212.       getEntryArea (ptr, i, r, vis);
  1213.       IF vis & RectFuncs.IsInRect (x, y, r)
  1214.       THEN
  1215.         idx := i;
  1216.         RETURN TRUE
  1217.       END;
  1218.     END;
  1219.   END;
  1220.   RETURN FALSE;
  1221. END findEntry;
  1222.  
  1223. PROCEDURE openSelected (ptr : treeWdwPtr; idx: CARDINAL; doNotTop, withCtrl: BOOLEAN);
  1224.   VAR firstSel : CARDINAL;
  1225.       isOpen   : BOOLEAN;
  1226.       window   : INTEGER;
  1227.       group,
  1228.       mess     : CARDINAL;
  1229. BEGIN
  1230.   WITH ptr^ DO
  1231.     IF (grinWindow >= 0) 
  1232.     THEN
  1233.       isOpen := FALSE;
  1234.       IF ~withCtrl & 
  1235.          grin.grinWindowTop (grinWindow) & 
  1236.          (grin.ActualGroupNr (grinWindow) = grHandle^.group)
  1237.       THEN
  1238.         isOpen := grin.grinSwitchTo (grinWindow, tree^[idx].msgNum, grin.grinNextMess, 0, doNotTop);
  1239.       END;
  1240.       IF ~isOpen
  1241.       THEN
  1242.         window := grin.grinOpenMessage (grHandle^.group, tree^[idx].msgNum, grin.grinNextMess, 0, grin.mOther);
  1243.         (* Nun Anfragen, welches Grinfenster nun top ist *)
  1244.         IF (window >= 0) & grin.grinWindowTop (window)
  1245.          & grin.getBasicInfo (window, group, mess, v.lcard)
  1246.          & (group = grHandle^.group) & (mess = tree^[idx].msgNum)
  1247.         THEN
  1248.           grinWindow := window;
  1249.         ELSE
  1250.           grinWindow := -1;
  1251.         END;
  1252.       END;
  1253.     END;
  1254.   END;
  1255. END openSelected;
  1256.  
  1257. PROCEDURE clickInTreeWindow(win, vdiH : INTEGER; special : ADDRESS; x,y : INTEGER; kstate : BITSET; buts: BITSET; clicks : INTEGER): BOOLEAN;
  1258.   VAR transY : INTEGER;
  1259.       ptr    : treeWdwPtr;
  1260.       entrySelected : BOOLEAN;
  1261.       line   : INTEGER;
  1262.       but    : BITSET;
  1263.       isOpen : BOOLEAN;
  1264.       ob     : INTEGER;
  1265.       clip   : GrafBase.Rectangle;
  1266.       kshift : BITSET;
  1267.       p      : GrafBase.Point;
  1268.       
  1269.       idx    : CARDINAL;
  1270.  
  1271.     PROCEDURE selectArea;
  1272.       VAR i        : CARDINAL;
  1273.           r        : GrafBase.Rectangle;
  1274.           rect     : GrafBase.Rectangle;
  1275.           first    : BOOLEAN;
  1276.           clip     : GrafBase.Rectangle;
  1277.           vis      : BOOLEAN;
  1278.     BEGIN
  1279.       WITH ptr^ DO
  1280.         rect := GrafBase.Rectangle{x, y, 0, 0};
  1281.         mtAppl.MouseFinger ();
  1282.         MagicAES.GrafRubberbox (x, y, -32767, -32767, rect.w, rect.h);
  1283.         mtAppl.MouseArrow();
  1284.         
  1285.         WITH rect DO
  1286.           IF w < 0
  1287.           THEN
  1288.             INC(x, w);
  1289.             w := -w
  1290.           END;
  1291.           IF h < 0
  1292.           THEN
  1293.             INC (y, h);
  1294.             h := -h
  1295.           END;
  1296.         END;
  1297.         
  1298.         (* clippen *)
  1299.         rect := RectFuncs.ClipRect (rect, treeWork);
  1300.         rect.h := BinOps.LowerInt (rect.h, treeWork.y + treeWork.h - 1 - rect.y);
  1301.  
  1302.         first := TRUE;
  1303.         FOR i := 0 TO treeElems - 1 DO
  1304.           (* Jetzt prfen, ob das Element berhrt wird *)
  1305.           getEntryArea (ptr, i, r, vis);
  1306.           IF vis
  1307.           THEN
  1308.             IF RectFuncs.rcIntersect (rect, r)
  1309.             THEN
  1310.               (* Eintrag selektieren und zeichnen *)
  1311.               tree^[i].selected := ~tree^[i].selected;
  1312.               getEntryArea (ptr, i, r, vis);
  1313.               IF vis
  1314.               THEN
  1315.                 IF first
  1316.                 THEN
  1317.                   clip := r;
  1318.                   first := FALSE;
  1319.                 ELSE
  1320.                   clip := GrafBase.FrameRects (clip, r);
  1321.                 END;
  1322.               END;
  1323.             END;
  1324.           END;
  1325.         END;
  1326.         IF ~first THEN WdwManager.RedrawWdw (wdw, clip); END;
  1327.       END;
  1328.     END selectArea;
  1329.  
  1330. BEGIN
  1331.   ptr := treeWdwPtr (special);
  1332.   WITH ptr^ DO
  1333.     (*
  1334.     (* Hier noch Baumposition anpassen *)
  1335.     WdwManager.GetWdwWork (wdw, clip);
  1336.     AdjustTreePos (clip, butWork); 
  1337.     IF RectFuncs.IsInRect (x, y, butWork)
  1338.     THEN
  1339.       (* Ist noch aus Stichwortliste, muž noch an B„ume angepažt werden
  1340.        *)
  1341.       ob := MagicAES.ObjcFind (butBox,  0, 8, x, y);
  1342.       IF (ob >= MausTauschrsc.listsel) & (ob <= MausTauschrsc.listread)
  1343.       THEN
  1344.         RETURN handleButtons (ptr, ob, kstate);
  1345.       END;
  1346.     ELS
  1347.     *)
  1348.     IF RectFuncs.IsInRect (x, y, treeWork)
  1349.     THEN
  1350.       IF ~CatGlobal.WithShift (kstate)
  1351.       THEN
  1352.         (* Alte deselektieren *)
  1353.         deselectEntries (ptr);
  1354.       END;
  1355.       (* Selektierten Eintrag finden *)
  1356.       IF findEntry (ptr, x, y, idx)
  1357.       THEN
  1358.         (* Eintrag selektieren *)
  1359.         tree^[idx].selected := ~tree^[idx].selected;
  1360.         redrawEntry (ptr, idx);
  1361.         (* Warten auf loslassen *)
  1362.         REPEAT
  1363.           MagicAES.GrafMkstate (x, y, but, v.bset);
  1364.         UNTIL but={};
  1365.         IF (clicks > 1) OR (~(0 IN buts) & (1 IN buts))
  1366.         THEN
  1367.           openSelected (ptr, idx, ~(0 IN buts) & (1 IN buts), CatGlobal.WithCtrl (kstate));
  1368.         END;
  1369.       ELSE
  1370.         MagicAES.GrafMkstate (p.x, p.y, but, kstate);
  1371.         IF 0 IN but
  1372.         THEN
  1373.           (* Graf-Rubberbox aufrufen *)
  1374.           selectArea();
  1375.         END;
  1376.       END;
  1377.       RETURN TRUE;
  1378.     END;
  1379.   END;
  1380.   RETURN FALSE;
  1381. END clickInTreeWindow;
  1382.  
  1383. PROCEDURE handleTreeKey (wdw, vdiH : INTEGER; special : ADDRESS; taste: INTEGER; char, scan : CHAR; kstate : BITSET) : BOOLEAN;
  1384.   VAR ptr : treeWdwPtr;
  1385.       gemCh : CARDINAL;
  1386.       key   : MOSGlobals.Key;
  1387.       ctrl  : BOOLEAN;
  1388.       shift : BOOLEAN;
  1389.       done  : BOOLEAN;
  1390.       doc   : GrafBase.LongRect;
  1391.       firstSel  : CARDINAL;
  1392.       selChanged: BOOLEAN;
  1393. BEGIN
  1394.   ptr := treeWdwPtr (special);
  1395.   WITH ptr^ DO
  1396.     gemCh := ORD(scan) * 256 + ORD(char);
  1397.     Keyboard.GemCharToKey (gemCh,  SHORT (INTEGER(kstate)), key);
  1398.     ctrl := CatGlobal.WithCtrl (kstate);
  1399.     shift := CatGlobal.WithShift (kstate);
  1400.     done := TRUE;
  1401.     IF Keyboard.IsSpecial (key)
  1402.     THEN
  1403.       CASE Keyboard.SpecialKey (key) OF
  1404.         left          : WdwManager.ScrollLeft (wdw, 1);  |
  1405.         soln          : WdwManager.PageLeft (wdw);    |
  1406.         right         : WdwManager.ScrollRight (wdw, 1); | 
  1407.         eoln          : WdwManager.PageRight (wdw);   |
  1408.         up            : WdwManager.ScrollUp (wdw, 1); |
  1409.         down          : WdwManager.ScrollDown (wdw, 1); |
  1410.         pgUp          : WdwManager.PageUp (wdw);      |
  1411.         pgDown        : WdwManager.PageDown (wdw);    |
  1412.         altC          : document.x := 0;
  1413.                         document.y := 0;
  1414.                         IF treeType = tVertical
  1415.                         THEN
  1416.                           treeType := tHorizontal;
  1417.                         ELSE
  1418.                           treeType := tVertical;
  1419.                         END;
  1420.                         iTreeSetFont (wdw, font, fontSize, FALSE); 
  1421.                         centerSelection (ptr, TRUE); |
  1422.         altZ          : document.x := 0;
  1423.                         document.y := 0;
  1424.                         IF zoomMode = zmNormal
  1425.                         THEN
  1426.                           zoomMode := zmZoom;
  1427.                         ELSE
  1428.                           zoomMode := zmNormal;
  1429.                         END;
  1430.                         iTreeSetFont (wdw, font, fontSize, FALSE); 
  1431.                         centerSelection (ptr, TRUE); |
  1432.       ELSE
  1433.         done := FALSE
  1434.       END;
  1435.     ELSE
  1436.       done := FALSE;
  1437.     END;
  1438.     RETURN done;
  1439.   END;
  1440.   RETURN FALSE
  1441. END handleTreeKey;
  1442.  
  1443. PROCEDURE handleTreeTimer (wdw, vdiH : INTEGER; special : ADDRESS): BOOLEAN;
  1444. BEGIN
  1445.   RETURN FALSE
  1446. END handleTreeTimer;
  1447.  
  1448. PROCEDURE closeTreeWindow (wdw, vdiH : INTEGER; special : ADDRESS; force : BOOLEAN) : BOOLEAN;
  1449.   VAR ptr : treeWdwPtr;
  1450.       varName : CatTypes.String255;
  1451.       full    : GrafBase.Rectangle;
  1452. BEGIN
  1453.   ptr := treeWdwPtr (special);
  1454.   WITH ptr^ DO
  1455.     Strings.Concat (cTreeWdw, StrConv.IntToStr (number, 0), varName, v.bool);
  1456.     WdwManager.GetWdwSize  (wdw, full); (* Gr”že des Fensters abfragen *)
  1457.     v.bool := ConfVars.SetConfigRect (varName, full);
  1458.     Strings.Concat (cTreeFont, StrConv.IntToStr (number, 0), varName, v.bool);
  1459.     v.bool := ConfVars.SetConfigInt (varName, font);
  1460.     Strings.Concat (cTreeSize, StrConv.IntToStr (number, 0), varName, v.bool);
  1461.     v.bool := ConfVars.SetConfigInt (varName, fontSize);
  1462.     ClearNum (number);
  1463.     FontSelect.UnloadFonts (vdi);
  1464.   END;
  1465.   (* Speicher freigeben *)
  1466.   DEALLOCATE (ptr^.tree, 0);
  1467.   freeOffset (ptr^.horizontal);
  1468.   freeOffset (ptr^.vertical);
  1469.   handlePool.FreeOneDataHandle(ptr^.grHandle);
  1470.   handlePool.FreeOnePtr(ptr, windows);
  1471.   RETURN TRUE
  1472. END closeTreeWindow;
  1473.  
  1474. PROCEDURE topTreeWdw (wdw, vdiH : INTEGER; special : ADDRESS) : BOOLEAN;
  1475. BEGIN
  1476.   RETURN TRUE;
  1477. END topTreeWdw;
  1478.  
  1479. PROCEDURE untopTreeWdw (wdw, vdiH : INTEGER; special : ADDRESS);
  1480. END untopTreeWdw;
  1481.  
  1482. PROCEDURE updateTreeWdw (wdw, vdiH : INTEGER; special : ADDRESS; update : BOOLEAN);
  1483. BEGIN
  1484.   IF update
  1485.   THEN
  1486.     MagicAES.WindUpdate (MagicAES.BEGUPDATE);
  1487.     mtAppl.MouseOff();
  1488.   ELSE
  1489.     mtAppl.MouseOn();
  1490.     MagicAES.WindUpdate (MagicAES.ENDUPDATE);
  1491.   END;
  1492. END updateTreeWdw;
  1493.  
  1494. PROCEDURE hideTreeWdw (wdw, vdiH : INTEGER; special : ADDRESS; hide : BOOLEAN);
  1495.   VAR ptr : treeWdwPtr;
  1496. BEGIN
  1497. END hideTreeWdw;
  1498.  
  1499. PROCEDURE setTreeWork (wdw, vdiH : INTEGER; special : ADDRESS; doc : GrafBase.LongRect; slided : BOOLEAN);
  1500.   VAR ptr : treeWdwPtr;
  1501. BEGIN
  1502.   ptr := treeWdwPtr (special);
  1503.   WITH ptr^ DO
  1504.     document := doc;
  1505.   END;
  1506. END setTreeWork;
  1507.  
  1508. PROCEDURE snapTreeWdw (wdw, vdiH : INTEGER; special : ADDRESS; VAR work : GrafBase.Rectangle);
  1509.   CONST minWindWidth = 128;
  1510.         minWindHeight = 128;
  1511.   VAR ptr       : treeWdwPtr;
  1512. BEGIN
  1513.   ptr := treeWdwPtr (special);
  1514.   WITH ptr^ DO
  1515.     IF font >= 0
  1516.     THEN
  1517.       WITH work DO
  1518.         treeWork := work;
  1519.         WdwManager.SetScrollParms (wdw, w-charWidth, h-charHeight, charWidth, charHeight);
  1520.       END;
  1521.     END;
  1522.   END;
  1523. END snapTreeWdw;
  1524.  
  1525. PROCEDURE getTreeScroll (wdw, vdiH : INTEGER; special : ADDRESS; VAR work : GrafBase.Rectangle);
  1526.   VAR ptr       : treeWdwPtr;
  1527.       varName   : ARRAY [0..255] OF CHAR;
  1528.       full      : GrafBase.Rectangle;
  1529. BEGIN 
  1530.   ptr := treeWdwPtr (special);
  1531.   WITH work DO
  1532.     WdwManager.SetScrollParms (wdw, w-ptr^.charWidth, h - ptr^.charHeight, ptr^.charWidth, ptr^.charHeight);
  1533.     ptr^.treeWork := work;
  1534.   END;
  1535.   WITH ptr^ DO
  1536.     IF wdw >= 0
  1537.     THEN
  1538.       Strings.Concat (cTreeWdw, StrConv.IntToStr (number, 0), varName, v.bool);
  1539.       WdwManager.GetWdwSize (wdw, full);                (* Gr”že des Fensters abfragen *)
  1540.       v.bool := ConfVars.SetConfigRect (varName, full);
  1541.     END;
  1542.   END;
  1543. END getTreeScroll;
  1544.  
  1545. PROCEDURE MakeTitle (gruppe: CARDINAL; VAR title: ARRAY OF CHAR);
  1546. BEGIN
  1547.   GroupSelect.GroupName (gruppe, title);
  1548.   ConfVars.GetConfDefBool (cSetAppName, v.bool, TRUE);
  1549.   IF CatGlobal.multiTask & v.bool
  1550.   THEN
  1551.     MagicStrings.Insert ('[CAT] ', title, 0);
  1552.   END;
  1553.   MagicStrings.Insert (' ', title, 0);
  1554.   MagicStrings.Append (' ', title);
  1555. END MakeTitle;
  1556.  
  1557. VAR treeCounter     : CARDINAL;
  1558.     globalTree      : treeArrayPtr;
  1559.  
  1560. PROCEDURE treeCount (hdl: data.OneGroupHandle; msgIdx: CARDINAL; mess: dataSys.pBlockPtr);
  1561. BEGIN
  1562.   INC (treeCounter);
  1563. END treeCount;
  1564.  
  1565. PROCEDURE treeBuild (hdl: data.OneGroupHandle; msgIdx: CARDINAL; msg: dataSys.pBlockPtr);
  1566.   VAR tmpStr: CatTypes.String255; 
  1567.       line : tShortText;
  1568.       mess : data.MessageType;
  1569.       maxLen: CARDINAL;
  1570.       i     : CARDINAL;
  1571.       p, n  : INTEGER;
  1572.  
  1573.     PROCEDURE CheckAssign (strPtr: CatTypes.Str255Ptr; VAR str : ARRAY OF CHAR);
  1574.     BEGIN
  1575.       IF strPtr # NIL
  1576.       THEN
  1577.         Strings.Assign (strPtr^, str, v.bool);
  1578.       ELSE
  1579.         Strings.Assign ("", str, v.bool);
  1580.       END;
  1581.     END CheckAssign;
  1582.     
  1583. BEGIN
  1584.   WITH globalTree^[treeCounter] DO
  1585.     msgNum := msgIdx;
  1586.     selected := FALSE;
  1587.     (* Erstmal die Messagenummern eintragen *)
  1588.     up      := msg^.upMess;
  1589.     down    := msg^.downMess;
  1590.     right   := msg^.rightMess;
  1591.     left    := msg^.leftMess;
  1592.     (* Jetzt die Daten lesen *)
  1593.     data.ReadHeader (hdl, msgIdx, mess);
  1594.     IF data.error = data.noError
  1595.     THEN
  1596.       (* Flags zuweisen *)
  1597.       flags := mess.StatusBits;
  1598.       (* Jetzt die Texte *)
  1599.       IF mess.EigeneNachricht & (mess.Gruppe = dataSys.private)
  1600.       THEN
  1601.         Strings.Assign ('An: ', line, v.bool);
  1602.         CheckAssign (mess.Empfaenger, tmpStr);
  1603.         maxLen := SIZE (line)- 5;
  1604.       ELSE
  1605.         CheckAssign (mess.Absender, tmpStr);
  1606.         line[0]:= '';
  1607.         maxLen := SIZE (line)-1;
  1608.       END;
  1609.       CatGlobal.KurzName (tmpStr, tmpStr, maxLen);
  1610.       (*
  1611.       IF LENGTH (tmpStr) > maxLen
  1612.       THEN
  1613.         (* Erstmal Vornamen abkrzen *)
  1614.         p := 0;
  1615.         p := Strings.Pos (' ', tmpStr, 0);
  1616.         IF p > 0
  1617.         THEN
  1618.           n := Strings.Pos ('@', tmpStr, 0);
  1619.           IF (n > 0) & (n-2 < p)
  1620.           THEN
  1621.             (* Hinter dem @ abschneiden, da kein richtiger Vorname *)
  1622.             tmpStr [n] := 0C;
  1623.           ELSE
  1624.             (* Vornamen verkrzen *)
  1625.             Strings.Delete (tmpStr, 1, p-1, v.bool);
  1626.             Strings.Insert ('.', 1, tmpStr, v.bool);
  1627.           END;
  1628.         END;
  1629.       END;
  1630.       IF LENGTH (tmpStr) > maxLen
  1631.       THEN 
  1632.         (* Eventuell Adresse abschneiden *)
  1633.         n := Strings.Pos ('@', tmpStr, 0);
  1634.         IF (n >= 0)
  1635.         THEN
  1636.           (* Ab dem @ abschneiden *)
  1637.           tmpStr [n] := 0C;
  1638.         END;
  1639.       END;
  1640.       IF LENGTH (tmpStr) > maxLen 
  1641.       THEN 
  1642.         (* Zu lang, hinten Pfeil nach rechts anh„ngen *)
  1643.         tmpStr[maxLen-1] := 3C;
  1644.         tmpStr[maxLen] := 0C;
  1645.       END;
  1646.       *)
  1647.       Strings.Append (tmpStr, line, v.bool);
  1648.       Strings.Assign (line, name, v.bool);
  1649.       width := LENGTH (name);
  1650.       (* Jetzt noch das Stichwort *)
  1651.       CheckAssign (mess.Betreff, tmpStr);
  1652.       maxLen := SIZE (line) - 1;
  1653.       IF LENGTH (tmpStr) > maxLen
  1654.       THEN
  1655.         (* Zu lang, hinten Pfeil nach rechts anh„ngen *)
  1656.         tmpStr[maxLen-1] := 3C;
  1657.         tmpStr[maxLen] := 0C;
  1658.       END;
  1659.       width := BinOps.HigherInt (LENGTH (tmpStr), width);
  1660.       Strings.Assign (tmpStr, betreff, v.bool);
  1661.       (* Speicher wieder freigeben *)
  1662.       DEALLOCATE (mess.InfoStrings, 0);
  1663.     END; (* IF data.error *)
  1664.   END;
  1665.   INC (treeCounter);
  1666. END treeBuild;
  1667.  
  1668. PROCEDURE getTreeDepth (tree: treeArrayPtr; idx: CARDINAL; depth: CARDINAL; VAR maxDepth: CARDINAL);
  1669.   VAR i : CARDINAL;
  1670. BEGIN
  1671.   INC (depth);
  1672.   IF depth > maxDepth THEN maxDepth := depth END;
  1673.   i := idx;
  1674.   WHILE i < dataSys.notSaved DO
  1675.     IF tree^[i].down < dataSys.notSaved THEN
  1676.       getTreeDepth (tree, tree^[i].down, depth, maxDepth);
  1677.     END;
  1678.     i := tree^[i].right;
  1679.   END;
  1680.   DEC (depth);
  1681. END getTreeDepth;
  1682.  
  1683. PROCEDURE findMsgIdx (ptr: treeWdwPtr; VAR idx: CARDINAL);
  1684.   VAR i : CARDINAL;
  1685. BEGIN
  1686.   WITH ptr^ DO
  1687.     FOR i := 0 TO treeCounter - 1 DO
  1688.       IF tree^[i].msgNum = idx
  1689.       THEN
  1690.         idx := i;
  1691.         RETURN
  1692.       END;
  1693.     END; (* for *)
  1694.   END;
  1695. END findMsgIdx;
  1696.  
  1697. PROCEDURE buildTree (ptr : treeWdwPtr; handle: handlePool.oneHandlePtr; msg: CARDINAL): BOOLEAN;
  1698.   VAR mess : data.MessageType;
  1699.       place: GrafBase.Rectangle;
  1700.       i, j : CARDINAL;
  1701.       mem  : LONGCARD;
  1702. BEGIN
  1703.   WITH ptr^ DO
  1704.     (* Erstmal Speicher fr die Offsetarray allozieren *)
  1705.     vertical := createOffset (128);
  1706.     IF vertical = NIL THEN RETURN FALSE END;
  1707.     horizontal := createOffset (128);
  1708.     IF horizontal = NIL THEN freeOffset (vertical); RETURN FALSE END;
  1709.     (* Konfigvariablen auslesen *)
  1710.     ConfVars.GetConfDefInt (cTreeUpLevels, maxUpLevels, 20); 
  1711.     ConfVars.GetConfDefInt (cTreeMaxDepth, maxTreeDepth, 40); 
  1712.     (* Objekte im Baum z„hlen *)
  1713.     treeCounter := 0;
  1714.     (*
  1715.     data.WalkTree (handle^.Zugriff, msg, TRUE, treeCount);
  1716.     *)
  1717.     data.WalkTree2 (handle^.Zugriff, msg, maxUpLevels, maxTreeDepth, treeCount);
  1718.     (* Jetzt Speicher allozieren *)
  1719.     treeElems := treeCounter;
  1720.     mem := LONG (treeCounter) * TSIZE (treeElem);
  1721.     ALLOCATE (tree, mem);
  1722.     IF tree = NIL THEN 
  1723.       freeOffset (horizontal);
  1724.       freeOffset (vertical);
  1725.       RETURN FALSE 
  1726.     END;
  1727.     (* Speicher l”schen, damit die Strings nicht einzeln gel”scht werden 
  1728.      * mssen
  1729.      *)
  1730.     Block.Clear (tree, mem);
  1731.     (* Speicher ist da, jetzt Baum aufbauen. Dabei muž ich danach die Indizes 
  1732.      * nochmal umrechnen! *)
  1733.     treeCounter := 0;
  1734.     globalTree := tree;
  1735.     (*
  1736.     data.WalkTree (handle^.Zugriff, msg, TRUE, treeBuild);
  1737.     *)
  1738.     data.WalkTree2 (handle^.Zugriff, msg, maxUpLevels, maxTreeDepth, treeBuild);
  1739.     (* Wir haben jetzt einen Baum. Jetzt mssen wir die Indizes noch anpassen, 
  1740.      * daher gebe ich die jetzt erstmal aus.
  1741.      *)
  1742.     (* so, jetzt mssen wir die Indizes noch anpassen *)
  1743.     FOR i := 0 TO treeCounter - 1 DO
  1744.       findMsgIdx (ptr, tree^[i].up);
  1745.       findMsgIdx (ptr, tree^[i].down);
  1746.       findMsgIdx (ptr, tree^[i].right);
  1747.       findMsgIdx (ptr, tree^[i].left);
  1748.     END;
  1749.     (* Jetzt mssen noch alle Treeindizes, die nicht im erlaubten Bereich 
  1750.      * liegen (0..treeElems-1) auf empty gesetzt werden, da ja nur ein 
  1751.      * Teilbaum vorhanden ist
  1752.      *)
  1753.     FOR i := 0 TO treeCounter - 1 DO
  1754.       IF tree^[i].up >= treeCounter THEN tree^[i].up := dataSys.empty END;
  1755.       IF tree^[i].down >= treeCounter THEN tree^[i].down := dataSys.empty END;
  1756.       IF tree^[i].left >= treeCounter THEN tree^[i].left := dataSys.empty END;
  1757.       IF tree^[i].right >= treeCounter THEN tree^[i].right := dataSys.empty END;
  1758.       IF tree^[i].msgNum = msg THEN tree^[i].selected := TRUE END;
  1759.     END;
  1760.     RETURN TRUE;
  1761.   END;
  1762. END buildTree;
  1763.  
  1764. PROCEDURE treeOpen (gruppe, which : CARDINAL; grinWdw : INTEGER);
  1765.   VAR ptr       : treeWdwPtr;
  1766.       handlePtr : handlePool.oneHandlePtr;
  1767.       varName   : ARRAY[0..39] OF CHAR;
  1768.       work      : GrafBase.Rectangle;
  1769.       comps     : BITSET;
  1770.       i         : CARDINAL;
  1771.       num       : INTEGER;
  1772.       infoLine  : CatTypes.String127;
  1773. BEGIN
  1774.   IF which >= dataSys.notSaved THEN RETURN END;
  1775.   IF handlePool.BlankToList(ptr, TSIZE(treeWindow), windows)
  1776.   THEN
  1777.     IF handlePool.GetOneDatahandle(gruppe, handlePtr)
  1778.     THEN
  1779.       ptr^.wdw := -1;
  1780.       ptr^.grHandle := handlePtr;
  1781.       ptr^.grinWindow := grinWdw;
  1782.       (* Fensternummer dieses Moduls herausfinden *)
  1783.       ptr^.number := FindNum ();
  1784.       Strings.Concat (cTreeWdw, StrConv.IntToStr (ptr^.number, 0), varName,
  1785.                       v.bool);
  1786.       IF ~ConfVars.GetConfigRect (varName, ptr^.treeWork) 
  1787.       THEN
  1788.         IF (ptr^.number > 0)
  1789.         THEN
  1790.           num := ptr^.number - 1;
  1791.           Strings.Concat (cTreeWdw, StrConv.IntToStr (num, 0), varName,
  1792.                           v.bool);
  1793.         END;
  1794.         ConfVars.GetConfDefRect (varName, ptr^.treeWork, EditTypes.deskSize);
  1795.         IF ~ RectFuncs.RectEqual (ptr^.treeWork, EditTypes.deskSize)
  1796.         THEN
  1797.           INC (ptr^.treeWork.x, 2*mtAppl.CharWidth);
  1798.           INC (ptr^.treeWork.y, mtAppl.CharHeight);
  1799.         END;
  1800.         Strings.Concat (cTreeWdw, StrConv.IntToStr (ptr^.number, 0), varName, v.bool);
  1801.         v.bool := ConfVars.SetConfigRect (varName, ptr^.treeWork);
  1802.       END;
  1803.       (* Fensterkomponenten setzen *)
  1804.       comps := {MagicAES.NAME..MagicAES.HSLIDE};
  1805.       MakeTitle (gruppe, ptr^.grName);
  1806.       IF data.LastMsgOfGroup (gruppe) = dataSys.empty
  1807.       THEN
  1808.         (* Gruppe ist leer! *)
  1809.         handlePool.FreeOneDataHandle(handlePtr);
  1810.         handlePool.FreeOnePtr (ptr, windows);
  1811.         ClearNum (ptr^.number);
  1812.         RETURN
  1813.       END;
  1814.       (* Jetzt den Baum aufbauen *)
  1815.       IF ~buildTree (ptr, handlePtr, which)
  1816.       THEN
  1817.         MTE.noMemAlert();
  1818.         RETURN
  1819.       END;
  1820.       (* Infozeile basteln *)
  1821.       MagicStrings.Assign (' ', infoLine);
  1822.       MagicStrings.Append (StrConv.CardToStr (ptr^.treeElems, 0), infoLine);
  1823.       MagicStrings.Append (' Nachricht', infoLine);
  1824.       IF ptr^.treeElems > 1 THEN 
  1825.         MagicStrings.Append ('en', infoLine);
  1826.       END;
  1827.       MagicStrings.Append (' in diesem Baum', infoLine);
  1828.       (* Fenster ”ffnen *)
  1829.       IF WdwManager.OpenWindow (clickInTreeWindow, handleTreeKey, handleTreeTimer, 
  1830.                                 EditTypes.deskSize, ptr^.treeWork, comps, TRUE, 
  1831.                                 infoLine, ptr^.grName, snapTreeWdw, closeTreeWindow, 
  1832.                                 drawTreeWdw, topTreeWdw, untopTreeWdw, updateTreeWdw,
  1833.                                 setTreeWork, getTreeScroll, hideTreeWdw, 
  1834.                                 0, ptr, FALSE, TRUE, TRUE, TRUE, 
  1835.                                 ptr^.wdw, ptr^.vdi)
  1836.       THEN
  1837.         WITH ptr^ DO
  1838.           (* Font aus Configvariablen lesen und setzen *)
  1839.           Strings.Concat (cTreeFont, StrConv.IntToStr (number, 0), varName,   v.bool);
  1840.           IF ~ConfVars.GetConfigInt (varName, font)
  1841.           THEN
  1842.             num := BinOps.HigherInt (number-1, 0);
  1843.             Strings.Concat (cTreeFont, StrConv.IntToStr (num, 0), varName,   v.bool);
  1844.             ConfVars.GetConfDefInt (varName, font, 1);
  1845.             Strings.Concat (cTreeSize, StrConv.IntToStr (num, 0), varName,
  1846.                             v.bool);
  1847.             ConfVars.GetConfDefInt (varName, fontSize, 10);
  1848.             
  1849.             Strings.Concat (cTreeFont, StrConv.IntToStr (number, 0), varName, v.bool);
  1850.             v.bool := ConfVars.SetConfigInt (varName, font);
  1851.             Strings.Concat (cTreeSize, StrConv.IntToStr (number, 0), varName, v.bool);
  1852.             v.bool := ConfVars.SetConfigInt (varName, fontSize);
  1853.           ELSE
  1854.             Strings.Concat (cTreeSize, StrConv.IntToStr (number, 0), varName, v.bool);
  1855.             ConfVars.GetConfDefInt (varName, fontSize, 10);
  1856.           END;
  1857.           (* Typ festlegen *)
  1858.           treeType := tVertical;
  1859.           zoomMode := zmNormal;
  1860.           (* Noch ein bižchen was fr die Window-Library *)
  1861.           WdwManager.SetNewDocument (wdw, document, FALSE);
  1862.           (* Fonts laden *)
  1863.           FontSelect.LoadFonts (vdi, v.int);
  1864.           (* Font setzen *)
  1865.           document.x := 0;
  1866.           document.y := 0;
  1867.           iTreeSetFont (wdw, font, fontSize, FALSE);
  1868.           
  1869.           (* Jetzt noch ein paar andere VDI-Variablen setzen *)
  1870.           v.int := MagicVDI.SetFillstyle (vdi, MagicVDI.Full);
  1871.           v.int := MagicVDI.SetFillinterior (vdi, MagicVDI.Full);
  1872.           v.int := MagicVDI.SetFillcolor (vdi, CatGlobal.treeBackCol);
  1873.           MagicVDI.SetUserlinestyle (vdi, $F0F0);
  1874.           (* Schreibmodus setzen *)
  1875.           v.int := MagicVDI.SetWritemode (vdi, MagicVDI.REPLACE);
  1876.  
  1877.           (* Und jetzt noch die erste selektierte Nachricht zentrieren 
  1878.            *)
  1879.           centerSelection (ptr, FALSE);
  1880.         END (* WITH *);
  1881.       ELSE
  1882.         (* Fenster konnte nicht ge”ffnet werden *)
  1883.         DEALLOCATE (ptr^.tree, 0);    (* Speicher freigeben *)
  1884.         v.int := mtAlerts.Alert (1,MTE.noWinOrWork);
  1885.       END (* IF openWindow *);
  1886.     ELSE
  1887.       (* Gruppe konnte nicht ge”ffnet werden *)
  1888.       handlePool.FreeOnePtr (ptr, windows);
  1889.       MTE.noMemAlert();
  1890.     END;
  1891.   ELSE
  1892.     (* Kein Platz mehr fr Fenstereintrag *)
  1893.     MTE.noMemAlert();
  1894.   END;
  1895. END treeOpen;
  1896.  
  1897. PROCEDURE treeClose (wdw : INTEGER);
  1898. (* Ein Baumfenster wird geschlossen *)
  1899.   VAR p : treeWdwPtr;
  1900. BEGIN
  1901.   IF handlePool.FindEntry(ADR(wdw), FindWinCond, windows, p) THEN
  1902.     v.bool := WdwManager.CloseWindow (wdw, TRUE);
  1903.   END;
  1904. END treeClose;
  1905.  
  1906. PROCEDURE treeCloseAll ();
  1907. (* Schliežt alle Fenster des Moduls
  1908.  *)
  1909. (* Alle Sichwortlistenfenster werden geschlossen *)
  1910.   VAR lauf : treeWdwPtr;
  1911. BEGIN
  1912.   Lists.ResetList(windows);
  1913.   lauf := Lists.NextEntry(windows);
  1914.   WHILE lauf # NIL DO
  1915.     treeClose(lauf^.wdw);
  1916.     lauf := Lists.NextEntry(windows);
  1917.   END;
  1918. END treeCloseAll;
  1919.  
  1920. PROCEDURE treeWindowTop (wdw : INTEGER) : BOOLEAN;
  1921. (* Ist ein Kommentarbaumfenster oben? *)
  1922. BEGIN
  1923.   RETURN handlePool.FindEntry(ADR(wdw), FindWinCond, windows, v.a);
  1924. END treeWindowTop;
  1925.  
  1926. PROCEDURE treeSetFont (wdw: INTEGER; font, fontSize : INTEGER);
  1927. (* Setzt den Font fr das Kommentarbaumfenster *)
  1928. BEGIN
  1929.   iTreeSetFont (wdw, font, fontSize, TRUE);
  1930. END treeSetFont;
  1931.  
  1932. PROCEDURE treeSetFlags(wdw : INTEGER; setBits, clearBits : BITSET);
  1933. (* Fr alle selektierten Nachrichten 
  1934.  * ein paar Flags setzen oder l”schen 
  1935.  *)
  1936.   VAR p : treeWdwPtr;
  1937.       bits,
  1938.       newBits : BITSET;
  1939.       i       : CARDINAL;
  1940.       (*$Reg*) counter : CARDINAL;
  1941.       vis      : BOOLEAN;
  1942.       first    : BOOLEAN;
  1943.       r, 
  1944.       clip     : GrafBase.Rectangle;
  1945. BEGIN
  1946.   IF handlePool.FindEntry(ADR(wdw), FindWinCond, windows, p) THEN
  1947.     WITH p^ DO
  1948.       CatGlobal.busyMouse();
  1949.       counter := 0;
  1950.       first := TRUE;
  1951.       FOR i := 0 TO treeElems-1 DO
  1952.         IF tree^[i].selected THEN 
  1953.           data.ReadState (grHandle^.Zugriff, tree^[i].msgNum, bits);
  1954.           IF data.error = data.noError
  1955.           THEN
  1956.             (* Neue Flags berechnen *)
  1957.             newBits := (bits-clearBits)+setBits;
  1958.             (* Flags setzen *)
  1959.             data.SetBits(grHandle^.Zugriff, tree^[i].msgNum, newBits);
  1960.             IF newBits # tree^[i].flags
  1961.             THEN
  1962.               tree^[i].flags := newBits;
  1963.               getEntryArea (p, i, r, vis);
  1964.               IF vis
  1965.               THEN
  1966.                 IF first
  1967.                 THEN
  1968.                   clip := r;
  1969.                   first := FALSE;
  1970.                 ELSE
  1971.                   clip := GrafBase.FrameRects (clip, r);
  1972.                 END;
  1973.               END;
  1974.             END;
  1975.             INC (counter);
  1976.             IF counter MOD 50 = 0 THEN CatGlobal.busyMouse(); END;
  1977.           END;
  1978.         END;
  1979.       END;
  1980.       mtAppl.MouseArrow();
  1981.     END;
  1982.     IF ~first THEN WdwManager.RedrawWdw (wdw, clip); END;
  1983.   END;
  1984. END treeSetFlags;
  1985.  
  1986. PROCEDURE treeSelectAll(wdw : INTEGER);
  1987. (* Alle Nachrichten in dem Fenster werden selektiert 
  1988.  *)
  1989.  VAR ptr      : treeWdwPtr;
  1990.      idx      : CARDINAL;
  1991.      (*$Reg*) counter : CARDINAL;
  1992.      first    : BOOLEAN;
  1993.      r, 
  1994.      clip     : GrafBase.Rectangle;
  1995.      vis      : BOOLEAN;
  1996. BEGIN
  1997.   IF handlePool.FindEntry(ADR(wdw), FindWinCond, windows, ptr) THEN
  1998.     WITH ptr^ DO
  1999.       first := TRUE;
  2000.       FOR idx := 0 TO treeElems - 1 DO
  2001.         IF ~tree^[idx].selected
  2002.         THEN
  2003.           tree^[idx].selected := TRUE;
  2004.           getEntryArea (ptr, idx, r, vis);
  2005.           IF vis
  2006.           THEN
  2007.             IF first
  2008.             THEN
  2009.               clip := r;
  2010.               first := FALSE;
  2011.             ELSE
  2012.               clip := GrafBase.FrameRects (clip, r);
  2013.             END;
  2014.           END;
  2015.         END;
  2016.       END;
  2017.       IF ~first THEN WdwManager.RedrawWdw (wdw, clip); END;
  2018.     END;
  2019.   END;
  2020. END treeSelectAll;
  2021.  
  2022. BEGIN
  2023.   Lists.CreateList (windows, v.bool);
  2024.   (*
  2025.   CatGlobal.treeBackCol := 0;
  2026.   CatGlobal.treeTextCol := 1;
  2027.   CatGlobal.treeLineCol := 1;
  2028.   *)
  2029.   maxUpLevels := 20; (* Sp„ter durch Configvariablen auslesen *)
  2030.   maxTreeDepth := 40; (* " *)
  2031. END treeList.